package server

import (
	"context"
	"runtime"

	"github.com/bytedance/gopkg/util/logger"
	"google.golang.org/grpc"
)

/*

实现了一个gRPC的拦截器函数RecoveryUnaryServerInterceptor。拦截器函数是在处理gRPC请求时执行的中间件函数。
该函数接受一个context.Context对象、一个请求对象req、一个grpc.UnaryServerInfo对象和一个grpc.UnaryHandler函数作为参数，并返回一个响应对象resp和一个错误对象err。

在函数内部，使用defer语句定义了一个匿名函数，用于捕获并处理可能发生的panic。如果发生了panic，会通过recover()函数捕获到panic的错误信息，并将错误信息和堆栈信息记录到日志中。

最后，调用handler(ctx, req)执行实际的请求处理逻辑，并返回处理结果。
*/

// RecoveryUnaryServerInterceptor recovery中间件最好放在第一个去执行
func RecoveryUnaryServerInterceptor() grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		defer func() {
			if err := recover(); err != nil {
				stack := make([]byte, 4096)
				stack = stack[:runtime.Stack(stack, false)]
				logger.CtxErrorf(ctx, "err:%v\nstack:%s", err, stack)
			}

		}()

		return handler(ctx, req)
	}
}

/*
recover()是Go语言中的一个内建函数，用于捕获并处理panic错误。当程序发生panic时，会中断当前的执行流程，并开始执行defer语句块中的代码。在defer语句块中，可以使用recover()函数来捕获panic的错误信息。

recover()函数的返回值类型是interface{}，它返回panic的值。如果没有发生panic或者在非defer语句块中调用recover()，它会返回nil。

通常，recover()函数会与defer语句一起使用，用于在发生panic时进行错误处理、日志记录或恢复程序的执行。通过捕获panic并处理错误，可以避免程序因为panic而崩溃，并且可以在错误发生时采取适当的措施

-- runtime.Stack()是Go语言运行时库中的一个函数，用于获取当前的堆栈信息。它接受一个字节切片作为参数，将当前的堆栈信息写入该切片，并返回写入的字节数。

*/
